/**
 *
 */
package com.rf.richfitwheel.workflow.service.impl;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.rf.richfitwheel.admin.sys.vo.UserVO;
import com.rf.richfitwheel.common.utils.R;
import com.rf.richfitwheel.workflow.feignclient.SysDicFeign;
import com.rf.richfitwheel.workflow.model.*;
import com.rf.richfitwheel.workflow.service.WfProcessPageService;
import com.rf.richfitwheel.workflow.service.WfProcessTaskService;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.StartEvent;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.activiti.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.delegate.ActivityBehavior;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.*;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.rf.richfitwheel.common.exception.BusinessException;
import com.rf.richfitwheel.common.utils.PageUtils;
import com.rf.richfitwheel.common.utils.StringUtils;
import com.rf.richfitwheel.common.utils.UuidUtil;
import com.rf.richfitwheel.workflow.entity.ProcessVO;
import com.rf.richfitwheel.workflow.service.ModelService;

/**
 * @author hushouquan
 *
 */
@Service
public class ModelServiceImpl implements ModelService {

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private WfProcessPageService wfProcessPageService;
    @Autowired
    private WfProcessTaskService wfProcessTaskService;
    @Autowired
    private SysDicFeign fSysDicFeign;

    @Override
    public void addOrUpdate(Map<String, Object> params, UserVO userVO) throws IOException {
        String id = params.get("id") == null ? null : params.get("id").toString();
        String orgCode = params.get("orgCode") == null ? null : params.get("orgCode").toString();
        String processName = params.get("processName") == null ? null : params.get("processName").toString();
        String processKey = params.get("processKey") == null ? null : params.get("processKey").toString();
        String processCode = params.get("processCode") == null ? null : params.get("processCode").toString();
        String modelId = params.get("modelId") == null ? null : params.get("modelId").toString();
        if (StringUtils.isBlank(id)) {
            if (StringUtils.isBlank(modelId)) {
                this.newModel(orgCode, processName, processKey, processCode, userVO);
            } else {
                this.copyModel(orgCode, processName, processKey, processCode, modelId, userVO);
            }
        } else {
            this.updateModel(id, orgCode, processName, processKey, processCode, userVO);
        }
    }

    @Override
    public PageUtils list(Map<String, Object> params, UserVO user) {
        String processCode = params.get("processCode") == null ? "" : params.get("processCode").toString();
        String processKey = params.get("processKey") == null ? "" : params.get("processKey").toString();
        String processName = params.get("processName") == null ? "" : params.get("processName").toString();
        int pageSize = Integer.parseInt(params.get("page").toString());
        int limit = Integer.parseInt(params.get("limit").toString());
        int offset = (pageSize - 1) * limit;
        ModelQuery query = repositoryService.createModelQuery();
        query.modelProcessCode(processCode);
        if (StringUtils.isNotBlank(processKey)) {
            query.modelKey(processKey);
        }
        if (StringUtils.isNotBlank(processName)) {
            query.modelNameLike("%" + processName + "%");
        }
        query.orderByLastUpdateTime().desc();
        List<Model> list = query.latestVersion().orderByCreateTime().desc().listPage(offset, limit);
        int total = (int) query.latestVersion().count();
        PageUtils pageUtils = new PageUtils(list, total);
        return pageUtils;

    }

    @Override
    public void deleteModel(String modelId) {
        Model model = repositoryService.createModelQuery().modelId(modelId).singleResult();
        wfProcessTaskService.deleteByProDefKey(model.getKey());
        repositoryService.deleteModel(modelId);
    }

    @Override
    public void deployModel(String id, UserVO userVO) throws Exception {
        String deploymentId = this.deploy1(id, userVO);
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).latestVersion().singleResult();
        if (processDefinition != null) {
            //读取节点信息保存到usertask表
            setActivitiInfo(processDefinition);
        } else {

        }
    }

    @Override
    public void deployModelExtendAndSetAuthor(Model model, WfStationProcess wfStationProcess, UserVO userVO, List<WfStationProcessOrder> wfStationProcessOrders) throws Exception {
        String deploymentId = this.deploy1(model.getId(), userVO);
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).latestVersion().singleResult();
        if (processDefinition != null) {
            List<WfProcessTask> wfProcessTasks = setActivitiInfo(processDefinition);//读取节点信息保存到usertask表
            int i = 0;
            for (WfProcessTask wfProcessTask : wfProcessTasks) {
                WfStationProcessOrder wspo = wfStationProcessOrders.get(i);
                wfProcessTask.setStationProcessOrderId(wspo.getId());
                if (StringUtils.isNotBlank(wspo.getPageCode())) {
                    WfProcessPage wfProcessPage = wfProcessPageService.getByPageCode(wspo.getPageCode());//根据目录编码和页面类型获取审批页面配置
                    wfProcessTask.setTaskName(wspo.getStationName());//更新岗位名称
                    if (!ObjectUtils.isEmpty(wfProcessPage)) {
                        wfProcessTask.setTaskUrl(wfProcessPage.getPageUrl());//更新审批地址
                    }
                }
                wfProcessTask.setTaskDetailUrl(processDefinition.getCategory());
                wfProcessTask.setAssigneeType("3");
                wfProcessTask.setCandidateIds(wspo.getStationId());
                R r = fSysDicFeign.getDicByClassCodeAndDataCode("MODULE", wspo.getModuleType());
                Map<String, Object> dictionary = (Map<String, Object>) r.get("dictionary");
                wfProcessTask.setCandidateNames(wspo.getOrgName() + "-" + wspo.getDeptName() + "-" + dictionary.get("dataName") + "-" + wspo.getStationName());
                this.wfProcessTaskService.updateWfProcessTask(wfProcessTask);
                i++;
            }
        } else {

        }

    }


    @Override
    public List<WfProcessTask> getWfProcessTaskByProDefKey(String proDefKey) {

        List<WfProcessTask> wfProcessTasks = this.wfProcessTaskService.findByProDefKey(proDefKey);
        return wfProcessTasks;
    }

    @Override
    public Model getById(String modelId) {
        ModelQuery query = repositoryService.createModelQuery();
        query.modelId(modelId);
        Model model = query.latestVersion().singleResult();
        return model;
    }

    @Override
    public Model findByOrgCodeAndProcessCode(String orgCode, String processCode) {
        ModelQuery query = repositoryService.createModelQuery();
        query.modelOrgCode(orgCode);
        query.modelProcessCode(processCode);
        Model model = query.latestVersion().singleResult();
        return model;
    }

    @Override
    public Model findByProcessKey(String processKey) {
        ModelQuery query = repositoryService.createModelQuery();
        query.modelKey(processKey);
        Model model = query.latestVersion().singleResult();
        return model;
    }


    private List<WfProcessTask> setActivitiInfo(ProcessDefinition processDefinition) throws Exception {
        List<WfProcessTask> wfProcessTasks = new ArrayList<>();
        this.wfProcessTaskService.deleteByProDefId(processDefinition.getId());
        ProcessDefinitionEntity processDef = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(processDefinition.getId());
        List<ActivityImpl> activities = processDef.getActivities();//获得当前任务的所有节点
        for (ActivityImpl activity : activities) {
            ActivityBehavior activityBehavior = activity.getActivityBehavior();

            //是否为用户任务
            if (activityBehavior instanceof UserTaskActivityBehavior || activityBehavior instanceof ParallelMultiInstanceBehavior || activityBehavior instanceof SequentialMultiInstanceBehavior) {
//                UserTaskActivityBehavior userTaskActivityBehavior = (UserTaskActivityBehavior) activityBehavior;
//                TaskDefinition taskDefinition = userTaskActivityBehavior.getTaskDefinition();
                //任务所属角色
                String taskDefKey = activity.getId();
                String taskName = activity.getProperties().get("name").toString();
                String taskType = activity.getProperty("type").toString();
                if (activity.getProperties().containsKey("multiInstance")) {
                    taskType = activity.getProperty("multiInstance").toString();
                }
                WfProcessTask wfProcessTask = new WfProcessTask();
                wfProcessTask.setTaskType(taskType);//用户任务
                wfProcessTask.setId(UuidUtil.get32UUID());
                wfProcessTask.setProcDefId(processDefinition.getId());
                wfProcessTask.setProcDefKey(processDefinition.getKey());
                wfProcessTask.setProcDefName(processDefinition.getName());
                wfProcessTask.setTaskDefKey(taskDefKey);
                wfProcessTask.setTaskName(taskName);
                this.wfProcessTaskService.addWfProcessTask(wfProcessTask);
                wfProcessTasks.add(wfProcessTask);
            }
        }
        return wfProcessTasks;
    }

    @Override
    public List<Model> getListByOrgCodeAndName(String orgCode, String processName) {
        ModelQuery query = repositoryService.createModelQuery();
        query.modelOrgCode(orgCode);
        query.modelNameLike("%" + processName + "%");
        query.orderByLastUpdateTime().desc();
        List<Model> list = query.latestVersion().orderByCreateTime().desc().list();
        return list;
    }


    /**
     * 初始化一个空的模型
     * @return
     */
    @Override
    public String newModel(UserVO user) {
        // 初始化一个空模型
        Model model = repositoryService.newModel();
        // 设置一些默认信息
        String name = "new-process";
        String description = "";
        int revision = 1;
        String key = "process";
        ObjectNode modelNode = objectMapper.createObjectNode();
        modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);
        model.setName(name);
        model.setKey(key);
        model.setMetaInfo(modelNode.toString());
        model.setTenantId(user.getTenantId());
        repositoryService.saveModel(model);
        String id = model.getId();
        // 完善ModelEditorSource
        ObjectNode editorNode = objectMapper.createObjectNode();
        editorNode.put("id", "canvas");
        editorNode.put("resourceId", "canvas");
        ObjectNode stencilSetNode = objectMapper.createObjectNode();
        stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
        editorNode.set("stencilset", stencilSetNode);
        repositoryService.addModelEditorSource(id, editorNode.toString().getBytes(StandardCharsets.UTF_8));
        return id;
    }

    /**
     * 初始化一个空的模型
     * @return
     */
    @Override
    public Model newModel(String orgCode, String processName, String processKey, String processCode, UserVO user) {
        // 初始化一个空模型
        Model model = repositoryService.newModel();
        model.setOrgCode(orgCode);
        model.setProcessCode(processCode);
        // 设置一些默认信息
        String description = "";
        int revision = 1;
        ObjectNode modelNode = objectMapper.createObjectNode();
        modelNode.put(ModelDataJsonConstants.MODEL_NAME, processName);
        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);
        model.setName(processName);
        model.setKey(processKey);
        model.setMetaInfo(modelNode.toString());
        //model.setTenantId(user.getTenantId());
        repositoryService.saveModel(model);
        String id = model.getId();
        // 完善ModelEditorSource
        ObjectNode editorNode = objectMapper.createObjectNode();
        editorNode.put("id", "canvas");
        editorNode.put("resourceId", "canvas");
        ObjectNode stencilSetNode = objectMapper.createObjectNode();
        stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
        editorNode.set("stencilset", stencilSetNode);

        ObjectNode properties = objectMapper.createObjectNode();
        properties.put("process_id", model.getKey());
        properties.put("process_author", "lms");
        properties.put("name", model.getName());
        editorNode.set("properties", properties);
        repositoryService.addModelEditorSource(id, editorNode.toString().getBytes(StandardCharsets.UTF_8));
        return model;
    }

    @Override
    public String copyModel(String orgCode, String processName, String processKey, String processCode, String modelId, UserVO userVO) throws IOException {
        Model sourceModel = repositoryService.getModel(modelId);
        ObjectNode sourceObjectNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelId));
        Model model = repositoryService.newModel();
        model.setOrgCode(orgCode);
        model.setProcessCode(processCode);
        // 设置一些默认信息
        String description = "";
        int revision = 1;
        ObjectNode modelNode = objectMapper.createObjectNode();
        modelNode.put(ModelDataJsonConstants.MODEL_NAME, processName);
        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);
        model.setName(processName);
        model.setKey(processKey);
        model.setMetaInfo(modelNode.toString());
        //model.setTenantId(user.getTenantId());
        repositoryService.saveModel(model);

        ObjectNode editorNode = sourceObjectNode.deepCopy();
        ObjectNode properties = editorNode.with("properties");
        properties.put("process_id", model.getKey());
        properties.put("process_author", "lms");
        properties.put("name", model.getName());
        repositoryService.addModelEditorSource(model.getId(), editorNode.toString().getBytes("utf-8"));
        return model.getId();
    }

    @Override
    public void updateModel(String modelId, String orgCode, String processName, String processKey, String processCode, UserVO userVO) {
        Model model = repositoryService.getModel(modelId);
        model.setOrgCode(orgCode);
        model.setProcessCode(processCode);
        // 设置一些默认信息
        String description = "";
        int revision = 1;
        ObjectNode modelNode = objectMapper.createObjectNode();
        modelNode.put(ModelDataJsonConstants.MODEL_NAME, processName);
        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);
        model.setName(processName);
        model.setKey(processKey);
        model.setMetaInfo(modelNode.toString());
        //model.setTenantId(user.getTenantId());
        repositoryService.saveModel(model);
    }


    /**
     * 复制并初始化一个空的模型
     * @return
     */
    public Model copyModel(String modelId) throws IOException {

        Model sourceModel = repositoryService.getModel(modelId);
        ObjectNode sourceObjectNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelId));


        Model model = repositoryService.newModel();
        model.setKey(sourceModel.getKey() + "_" + UuidUtil.get16NumUUID());
        model.setName(sourceModel.getName() + "_copy");
        model.setMetaInfo(sourceModel.getMetaInfo());
        model.setCategory(sourceModel.getCategory());
        //model.setVersion(1);
        model.setTenantId(model.getTenantId());
        repositoryService.saveModel(model);


        ObjectNode editorNode = sourceObjectNode.deepCopy();
        ObjectNode properties = editorNode.with("properties");
        properties.put("process_id", model.getKey());
        properties.put("process_author", "lms");
        properties.put("name", model.getName());
        editorNode.set("properties", properties);
        repositoryService.addModelEditorSource(model.getId(), editorNode.toString().getBytes("utf-8"));

        return model;
    }

    @Override
    public Model copyModel(String templateModelId, String modelId, String orgCode, String processName, String processKey, String processCode, List<WfStationProcessOrder> wfStationProcessOrders) throws IOException {
        Model sourceModel = repositoryService.getModel(templateModelId);
        ObjectNode sourceObjectNode = (ObjectNode) objectMapper.readTree(repositoryService.getModelEditorSource(templateModelId));
        Model model = repositoryService.getModel(modelId);
        model.setOrgCode(orgCode);
        model.setProcessCode(processCode);
        model.setKey(processKey);
        model.setName(processName);
        model.setMetaInfo(sourceModel.getMetaInfo());
        model.setCategory(sourceModel.getCategory());

        ObjectNode metaInfoNode = objectMapper.createObjectNode();
        // 设置一些默认信息
        String description = "";
        int revision = 1;
        metaInfoNode.put(ModelDataJsonConstants.MODEL_NAME, processName);
        metaInfoNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        metaInfoNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);
        model.setMetaInfo(metaInfoNode.toString());

        //model.setVersion(1);
        //model.setTenantId(model.getTenantId());
        repositoryService.saveModel(model);
        ObjectNode editorNode = sourceObjectNode.deepCopy();
        ObjectNode properties = editorNode.with("properties");
        JsonNode childShapes = editorNode.get("childShapes");
        int i = 0;
        for (JsonNode jsonNode : childShapes) {
            //System.out.println(jsonNode);
            ObjectNode copyJsonNode = (ObjectNode) jsonNode;
            String stencilId = jsonNode.get("stencil").get("id").asText();
            if (stencilId.equals("UserTask")) {
                ObjectNode proppertiesNode = copyJsonNode.with("properties");
                String taskKey = proppertiesNode.get("overrideid").asText();
                WfStationProcessOrder wfStationProcessOrder = wfStationProcessOrders.get(i);
                if (StringUtils.isNotBlank(wfStationProcessOrder.getTaskName())) {
                    proppertiesNode.put("name", wfStationProcessOrder.getTaskName());
                } else {
                    proppertiesNode.put("name", wfStationProcessOrder.getStationName());
                }
                ObjectNode usertaskassignmentNode = objectMapper.createObjectNode();
                ObjectNode assignmentNode = objectMapper.createObjectNode();
                ArrayNode candidateGroupsNode = objectMapper.createArrayNode();
                ObjectNode candidateGroupNode = objectMapper.createObjectNode();
                candidateGroupNode.put("value", wfStationProcessOrder.getStationId());
                candidateGroupNode.put("$$hashKey", "0B" + wfStationProcessOrder.getApproveOrder());
                candidateGroupsNode.add(candidateGroupNode);
                assignmentNode.set("candidateGroups", candidateGroupsNode);
                usertaskassignmentNode.set("assignment", assignmentNode);
                proppertiesNode.set("usertaskassignment", usertaskassignmentNode);
                if (org.apache.commons.lang3.StringUtils.isNotBlank(wfStationProcessOrder.getPageCode())) {
                    WfProcessPage wfProcessPage = wfProcessPageService.getByPageCode(wfStationProcessOrder.getPageCode());//根据目录编码和页面类型获取审批页面配置
                    if (!ObjectUtils.isEmpty(wfProcessPage)) {
                        proppertiesNode.put("formkeydefinition", wfProcessPage.getPageUrl());
                    }
                }
                i++;
            }
//            if (stencilId.equals("StartNoneEvent")) {
//                ObjectNode proppertiesNode = copyJsonNode.with("properties");
//                proppertiesNode.put("overrideid", model.getKey());
//                proppertiesNode.put("name", model.getName());
//            }
        }
        properties.put("process_id", model.getKey());
        properties.put("process_author", "lms");
        properties.put("name", model.getName());
        WfProcessPage wfProcessPage = wfProcessPageService.getByFolderCodeAndPageType(model.getProcessCode(), "0");
        if (!ObjectUtils.isEmpty(wfProcessPage)) {
            properties.put("process_namespace", wfProcessPage.getPageUrl());
        }
        repositoryService.addModelEditorSource(model.getId(), editorNode.toString().getBytes("utf-8"));
        return model;
    }

    @Override
    public void editMode(String modelId, Map<String, WfProcessTask> wfProcessTaskMap) throws IOException, TranscoderException {
        Model sourceModel = repositoryService.getModel(modelId);
        ObjectNode sourceObjectNode = (ObjectNode) objectMapper.readTree(repositoryService.getModelEditorSource(modelId));

        ObjectNode editorNode = sourceObjectNode.deepCopy();
        ObjectNode properties = editorNode.with("properties");
        JsonNode childShapes = editorNode.get("childShapes");
        int i = 0;
        for (JsonNode jsonNode : childShapes) {
            //System.out.println(jsonNode);
            ObjectNode copyJsonNode = (ObjectNode) jsonNode;
            String stencilId = jsonNode.get("stencil").get("id").asText();
            if (stencilId.equals("UserTask")) {
                ObjectNode proppertiesNode = copyJsonNode.with("properties");
                String taskKey = proppertiesNode.get("overrideid").asText();
                WfProcessTask wfProcessTask = wfProcessTaskMap.get(taskKey);

                ObjectNode usertaskassignmentNode = objectMapper.createObjectNode();
                ObjectNode assignmentNode = objectMapper.createObjectNode();
                String[] cids = wfProcessTask.getCandidateIds().split(",");
                if (wfProcessTask.getTaskType().equals("1")) {
                    assignmentNode.put("assignee", wfProcessTask.getCandidateIds());
                } else if (wfProcessTask.getTaskType().equals("2")) {
                    ArrayNode candidateUsersNode = objectMapper.createArrayNode();
                    for (String cid : cids) {
                        ObjectNode candidateUserNode = objectMapper.createObjectNode();
                        candidateUserNode.put("value", wfProcessTask.getCandidateIds());
                        candidateUserNode.put("$$hashKey", "0B" + i++);
                        candidateUsersNode.add(candidateUserNode);
                    }
                    assignmentNode.set("candidateUsers", candidateUsersNode);
                } else if (wfProcessTask.getTaskType().equals("3")) {
                    ArrayNode candidateGroupsNode = objectMapper.createArrayNode();
                    for (String cid : cids) {
                        ObjectNode candidateGroupNode = objectMapper.createObjectNode();
                        candidateGroupNode.put("value", wfProcessTask.getCandidateIds());
                        candidateGroupNode.put("$$hashKey", "0B" + i++);
                        candidateGroupsNode.add(candidateGroupNode);
                    }
                    assignmentNode.set("candidateGroups", candidateGroupsNode);
                }
                usertaskassignmentNode.set("assignment", assignmentNode);
                proppertiesNode.set("usertaskassignment", usertaskassignmentNode);
                if (org.apache.commons.lang3.StringUtils.isNotBlank(wfProcessTask.getTaskUrl())) {
                    proppertiesNode.put("formkeydefinition", wfProcessTask.getTaskUrl());
                }
            }
//            if (stencilId.equals("StartNoneEvent")) {
//                ObjectNode proppertiesNode = copyJsonNode.with("properties");
//                proppertiesNode.put("overrideid", model.getKey());
//                proppertiesNode.put("name", model.getName());
//            }
        }
        repositoryService.addModelEditorSource(modelId, editorNode.toString().getBytes("utf-8"));
    }

    @Override
    public PageUtils queryHistoryDefinitionPage(Map<String, Object> params) {
        int page = Integer.parseInt(params.get("page").toString());
        int limit = Integer.parseInt(params.get("limit").toString());
        String key = params.get("key").toString();
        ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery().processDefinitionKey(key);
        List<ProcessDefinition> list =
                query.orderByProcessDefinitionVersion()
                        .desc()
                        .listPage((page - 1) * limit, limit);
        int total = (int) query.count();
        List<ProcessVO> processVOList = new ArrayList<>(list.size());
        list.forEach(processDefinition -> {
            ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) processDefinition;
            ProcessVO processVO = new ProcessVO(processDefinition);
            processVO.setDeployTime(processDefinitionEntity.getDeploymentTime());
            processVO.setUsername(processDefinitionEntity.getDeploymentUser() != null ? processDefinitionEntity.getDeploymentUser() : null);
            processVOList.add(processVO);
        });
        PageUtils pageUtils = new PageUtils(processVOList, total);
        return pageUtils;
    }

    @Override
    public List<WfProcessTask> getWfProcessTaskByProDefId(String proDefId) {
        List<WfProcessTask> wfProcessTasks = this.wfProcessTaskService.findByProDefId(proDefId);
        return wfProcessTasks;
    }

    /**
     * 根据id加载模型数据
     * @param modelId
     * @return
     * @throws Exception
     */
    @Override
    public ObjectNode getEditorJson(String modelId) throws Exception {
        Model model = repositoryService.getModel(modelId);
        ObjectNode modelNode = null;
        if (model != null) {
            try {
                if (org.apache.commons.lang3.StringUtils.isNotEmpty(model.getMetaInfo())) {
                    modelNode = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
                } else {
                    modelNode = objectMapper.createObjectNode();
                    modelNode.put(ModelDataJsonConstants.MODEL_NAME, model.getName());
                }
                modelNode.put(ModelDataJsonConstants.MODEL_ID, model.getId());
                ObjectNode editorJsonNode = (ObjectNode) objectMapper
                        .readTree(new String(repositoryService.getModelEditorSource(model.getId()), StandardCharsets.UTF_8));
                modelNode.set("model", editorJsonNode);

            } catch (Exception e) {
                throw e;
            }
        }
        return modelNode;
    }

    /**
     * 删除一个空模型
     * @param modelId
     */
    @Override
    public void deleteNoneModel(String modelId) {
        Model model = repositoryService.getModel(modelId);
        if (model != null) {
            if (repositoryService.getModelEditorSourceExtra(model.getId()) == null) {
                repositoryService.deleteModel(model.getId());
            }
        }
    }


    /**
     * 获取最新版的流程定义
     * @return
     */
    @Override
    public List<ProcessDefinition> getProcessOption() {
        return repositoryService.createProcessDefinitionQuery().latestVersion().list();
    }

    @Override
    public void saveModel(String modelId, String name, String description, String json_xml, String svg_xml) throws Exception {
        Model model = repositoryService.getModel(modelId);

        ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());

        modelJson.put(ModelDataJsonConstants.MODEL_NAME, name);
        modelJson.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        model.setMetaInfo(modelJson.toString());
        model.setName(name);

        repositoryService.saveModel(model);
        ObjectNode sourceObjectNode = (ObjectNode) new ObjectMapper().readTree(json_xml.getBytes(StandardCharsets.UTF_8));
        repositoryService.addModelEditorSource(model.getId(), json_xml.getBytes(StandardCharsets.UTF_8));

        InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes(StandardCharsets.UTF_8));
        TranscoderInput input = new TranscoderInput(svgStream);

        PNGTranscoder transcoder = new PNGTranscoder();
        // Setup output
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        TranscoderOutput output = new TranscoderOutput(outStream);

        // Do the transformation
        transcoder.transcode(input, output);
        final byte[] result = outStream.toByteArray();
        repositoryService.addModelEditorSourceExtra(model.getId(), result);
        outStream.close();
    }

    @Override
    public void deploy(String modelId, UserVO user) throws Exception {
        // 获取模型
        Model modelData = repositoryService.getModel(modelId);
        byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
        Assert.notNull(bytes, "模型数据为空，请先设计流程并成功保存，再进行发布。");
        try {
            JsonNode modelNode = new ObjectMapper().readTree(bytes);
            BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
            String processName = modelData.getName() + ".bpmn20.xml";
//            modelData.setTenantId(tenantId);
            Assert.isTrue(model.getProcesses().size() > 0, "数据模型不符要求，请至少设计一条主线流程。");
            byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);
            /**
             * 发布流程
             */
            Deployment deployment = repositoryService.createDeployment()
                    .modelId(modelData.getId())
                    .name(modelData.getName())
                    .deploymentUser(user.getId())
                    .orgCode(modelData.getOrgCode())
                    .processCode(modelData.getProcessCode())
//                    .tenantId(modelData.getTenantId())
                    .addString(processName, new String(bpmnBytes, StandardCharsets.UTF_8))
                    .deploy();

            modelData.setDeploymentId(deployment.getId());
            repositoryService.saveModel(modelData); //更新模型信息表
        } catch (Exception ex) {
            System.out.println("===========发布流程失败：");
            ex.getStackTrace();
            ex.getMessage();
            throw new RuntimeException("流程发布失败！");
        }
    }

    @Override
    public String deploy1(String modelId, UserVO user) {
        // 获取模型
        Model modelData = repositoryService.getModel(modelId);
        byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
        Assert.notNull(bytes, "模型数据为空，请先设计流程并成功保存，再进行发布。");
        try {
            JsonNode modelNode = new ObjectMapper().readTree(bytes);
            BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
            String processName = modelData.getName() + ".bpmn20.xml";
//            modelData.setTenantId(tenantId);
            Assert.isTrue(model.getProcesses().size() > 0, "数据模型不符要求，请至少设计一条主线流程。");
            byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);

            /**
             * 发布流程
             */
            Deployment deployment = repositoryService.createDeployment()
                    .modelId(modelData.getId())
                    .name(modelData.getName())
                    .deploymentUser(user.getId())
                    .orgCode(modelData.getOrgCode())
                    .processCode(modelData.getProcessCode())
                    //.tenantId(modelData.getTenantId())
                    .addString(processName, new String(bpmnBytes, StandardCharsets.UTF_8))
                    .deploy();
            modelData.setDeploymentId(deployment.getId());
            repositoryService.saveModel(modelData); //更新模型信息表
            return deployment.getId();
        } catch (Exception ex) {
            throw new RuntimeException("流程发布失败！", ex);
        }
    }

    /**
     * 加载流程文件内容
     * @param deploymentId
     * @param resType
     * @param processDefinition
     * @return
     */
    @Override
    public InputStream resourceRead(String deploymentId, String resType, ProcessDefinition processDefinition) {
        String resourceName = "";
        if (resType.equals("image")) {
            resourceName = processDefinition.getDiagramResourceName();
        } else if (resType.equals("xml")) {
            resourceName = processDefinition.getResourceName();
        }

        InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
        return resourceAsStream;
    }

    /**
     * 流程导入
     * @param files
     * @param user
     */
    @Override
    public void improtDeploy(List<MultipartFile> files, UserVO user) throws Exception {
        for (MultipartFile file : files) {
            String fileName = file.getOriginalFilename().split("@")[1];

            InputStream fileInputStream = file.getInputStream();
            Deployment deployment = null;
            String extension = FilenameUtils.getExtension(fileName);
            String tenantId = file.getOriginalFilename().split("@")[0];
            /*if(org.apache.commons.lang.StringUtils.isBlank(tenantId)){
                tenantId = Constant.SUPER_ADMIN_TENANTID;
            }*/
            if (extension.equals("zip") || extension.equals("bar")) {
                ZipInputStream zip = new ZipInputStream(fileInputStream);
                deployment = repositoryService.createDeployment().addZipInputStream(zip).tenantId(tenantId).deploy();
            } else if (extension.equals("png")) {
                deployment = repositoryService.createDeployment().addInputStream(fileName, fileInputStream).tenantId(tenantId).deploy();
            } else if (fileName.indexOf("bpmn20.xml") != -1) {
                deployment = repositoryService.createDeployment().addInputStream(fileName, fileInputStream).tenantId(tenantId).deploy();
            } else if (extension.equals("bpmn")) { // bpmn扩展名特殊处理，转换为bpmn20.xml
                String baseName = FilenameUtils.getBaseName(fileName);
                deployment = repositoryService.createDeployment().addInputStream(baseName + ".bpmn20.xml", fileInputStream).tenantId(tenantId).deploy();
            } else {
                throw new BusinessException("不支持的文件类型：" + extension);
            }
            String procDefId = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult().getId();
            //将部署信息转换为模型
            org.activiti.engine.repository.Model modelData = convertToModel(procDefId);
        }
    }

    /**
     * 将流程转化为模型
     * @param procDefId
     * @return
     * @throws Exception
     */
    @Override
    public Model convertToModel(String procDefId) throws Exception {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId).singleResult();
        InputStream bpmnStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
                processDefinition.getResourceName());
        XMLInputFactory xif = XMLInputFactory.newInstance();
        InputStreamReader in = new InputStreamReader(bpmnStream, "UTF-8");
        XMLStreamReader xtr = xif.createXMLStreamReader(in);
        BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);

        BpmnJsonConverter converter = new BpmnJsonConverter();
        ObjectNode modelNode = converter.convertToJson(bpmnModel);
        org.activiti.engine.repository.Model modelData = repositoryService.newModel();
        modelData.setKey(processDefinition.getKey());
        modelData.setName(processDefinition.getName());
        modelData.setCategory(processDefinition.getCategory());//.getDeploymentId());
        modelData.setDeploymentId(processDefinition.getDeploymentId());
        modelData.setVersion(Integer.parseInt(String.valueOf(repositoryService.createModelQuery().modelKey(modelData.getKey()).count() + 1)));

        ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
        modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, processDefinition.getName());
        modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, modelData.getVersion());
        modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, processDefinition.getDescription());
        modelData.setMetaInfo(modelObjectNode.toString());
        modelData.setTenantId(processDefinition.getTenantId());

        repositoryService.saveModel(modelData);

        repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes("utf-8"));

        return modelData;
    }

    /**
     * 获取开始节点信息用于组织页面表单
     * @param defKey
     * @return
     */
    @Override
    public StartEvent getModelStartNodeInfo(String defKey) {
//		String defSql = "select def.*,dep.DEPLOY_TIME_ from ACT_RE_PROCDEF def,ACT_RE_DEPLOYMENT dep where def.DEPLOYMENT_ID_=dep.ID_ and def.KEY_='" + defKey + "' order by dep.DEPLOY_TIME_ desc";
//        List<Map<String, Object>> listDef = sqlAdapterMapper.selectSQL(defSql);
//        if(listDef.isEmpty()){
//            throw new BusinessException("没有获取到流程定义");
//        }
//        BpmnModel model = repositoryService.getBpmnModel(listDef.get(0).get("ID_").toString());
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionKey(defKey).latestVersion().latestVersion().list();
        if (list.isEmpty()) {
            return null;
        }
//        StartFormData startFormData = formService.getStartFormData(list.get(0).getId());
//        List<FormProperty> formProperties = startFormData.getFormProperties();
        BpmnModel model = repositoryService.getBpmnModel(list.get(0).getId());
        //获取流程所有节点信息
        // 获取所有节点
        Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();
        for (FlowElement e : flowElements) {
            if (e instanceof StartEvent) {
                StartEvent startEvent = (StartEvent) e;
//                ActivityImpl startEventActivityImpl = processDefinitionEntity.findActivity(startEvent.getId());// 当前节点
                return startEvent;
            }
        }
        return null;
    }

    /**
     * 查询流程名称列表
     * @param tenantId
     *
     * @return
     */
    @Override
    public List<ProcessVO> getProcessNameList(String tenantId) {
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionTenantId(tenantId).latestVersion().list();
        List<ProcessVO> processVOList = new ArrayList<>();
        list.forEach(item -> {
            ProcessVO processVO = new ProcessVO(item);
            processVOList.add(processVO);
        });
        //同一个流程发布多个租户后，流程名称会有重复
        List<ProcessVO> processVOs = new ArrayList<>();
        Map<String, Object> nameMap = new HashMap<>();
        for (ProcessVO processVO : processVOList) {
            if (!nameMap.containsKey(processVO.getName())) {
                nameMap.put(processVO.getName(), processVO);
                processVOs.add(processVO);
            }
        }
        return processVOs;
    }


}
